//****************************************************************************
//						f_timing_gen_03
//
//功能：TCON用帧输出时序产生
//版本：v1.0		yshao		2021/04/28
//					修改自f_timing_gen_03
//****************************************************************************

module f_timing_gen_03 (
        //时钟 & 复位
        input   wire            resetb,
        
        //模式设置
		input	wire			half_flag,
//		input	wire	[7:0]	test_mode_in,

        //设置接口
		input	wire	[23:0]	base_addr,

        //设置输出
		input	wire			set_clk,
		input	wire			set_d_ok,
		input	wire	[23:0]	set_addr,
		input	wire	[7:0]	set_data,
      
        output	wire	[11:0]	p_width,
        output	wire	[3:0]	lan_num,
        output	reg		[1:0]	VH_POLORITY,

        //输入帧同步
        input   wire            vsin,

        //帧缓冲输出时序
        input	wire			pclk,
        output  reg				vs_a,
        output  reg				de_a,
        output  reg				de_pre,
        
        //调试用图像数据
        output  reg		[31:0]	dout_t,
        
        //最终输出时序
        input	wire            oclk,
        output  reg             vsout,
        output  reg             hsout,
        output  reg             deout,
        output  reg		[47:0]	dout,
        
        //TCON辅助时序
        output	reg				TP,
        output	reg				POL,
        output  reg             STV,
        output  reg				CPV1,
        output  reg				CPV2,
        output  reg             CLR,
        
        output  wire    [7:0]   tout
        );

//**************************************************************/
//              参数设置
//**************************************************************/
//时序参数
/*parameter   T_H_DATA      = 13'd480;	//12'd240;
parameter   T_H_SYNC_S    = 13'd502;	//12'd251;   //12'd255
parameter   T_H_SYNC_E    = 13'd513;	//12'd256;   //12'd258
parameter   T_H_LENGTH    = 13'd550;	//12'd275;    
    
parameter   T_V_DATA      = 13'd2160;	//16'd4320;
parameter   T_V_SYNC_S    = 13'd2245;	//16'd4494;	//12'd4497
parameter   T_V_SYNC_E    = 13'd2247;	//16'd4498;	//12'd4499
parameter   T_V_LENGTH    = 13'd2250;	//16'd4500;
*/
parameter   VS_DIV			= 135_000_000 / 60;

parameter   T_H_ACTIVE 		= 1920;
// parameter   T_H_LENGTH 		= 2080;
parameter   T_H_LENGTH 		= 2248;
parameter   T_V_ACTIVE 		= 1080;
parameter   T_V_LENGTH 		= 1125;
parameter   T_P_LAN_NUM 	= 2;

parameter   T_V_SYNC_S  	= 13'd5; 
parameter   T_V_SYNC_E 		= T_V_SYNC_S + 13'd5; 
parameter   T_V_DATA_S 		= T_V_SYNC_E + 13'd5; 
parameter   T_V_DATA_E 		= T_V_DATA_S + T_V_ACTIVE;
parameter   T_H_SYNC_S  	= (T_H_ACTIVE + 64) / T_P_LAN_NUM;
parameter   T_H_SYNC_E 		= T_H_SYNC_S + 12;
parameter   T_VH_POLORITY	= 2'b00;

//**************************************************************/
//               信号定义
//**************************************************************/
reg		[1:0]	work_mode;
reg		[7:0]	test_mode;
reg		[13:0]	H_MAX, V_MAX, V_SYNC_S, V_SYNC_E;
reg		[13:0]	V_DATA_S, V_DATA_E, H_SYNC_S, H_SYNC_E, H_ACTIVE;
reg		[3:0]	P_LAN_NUM;
reg		[11:0]	p_length;

wire			work_en, dp_rec_mode;

(* MARK_DEBUG="true" *) reg     [13:0]  p_count, h_count;
reg             p_end, h_end;

reg				deout_t, deout_p, deout_pp;
reg		[4:0]	vsout_t, deout_p_t, deout_pp_t;
reg				de_flag, de_end;
(* MARK_DEBUG="true" *) reg		[9:0]	de_count, de_max;
(* MARK_DEBUG="true" *) reg		[11:0]	h_num;

   
//**************************************************************/
//               参数设置
//**************************************************************/
always  @(posedge set_clk or negedge resetb) begin
	if (resetb == 0) begin
		work_mode	<= 1;
		test_mode	<= 8'h02;
		H_MAX 		<= T_H_LENGTH / T_P_LAN_NUM - 2;
		V_MAX	 	<= T_V_LENGTH - 1;
		V_SYNC_S 	<= T_V_SYNC_S;
		V_SYNC_E 	<= T_V_SYNC_E;
		V_DATA_S 	<= T_V_DATA_S;
		V_DATA_E 	<= T_V_DATA_E;
		H_SYNC_S 	<= T_H_SYNC_S;
		H_SYNC_E 	<= T_H_SYNC_E;
		H_ACTIVE	<= T_H_ACTIVE;
		VH_POLORITY	<= T_VH_POLORITY;
		P_LAN_NUM	<= T_P_LAN_NUM;
		end
	else if (set_d_ok == 1)
		case (set_addr)
			base_addr + 24'h000000:		work_mode		<= set_data[1:0];
			base_addr + 24'h000004:		test_mode		<= set_data[7:0];
			base_addr + 24'h000008:		H_MAX[7:0]		<= set_data[7:0];
			base_addr + 24'h000009:		H_MAX[13:8] 	<= set_data[5:0];
			base_addr + 24'h00000C:		V_MAX[7:0]		<= set_data[7:0];
			base_addr + 24'h00000D:		V_MAX[13:8] 	<= set_data[5:0];
			base_addr + 24'h000010:		V_SYNC_S[7:0]	<= set_data[7:0];
			base_addr + 24'h000011:		V_SYNC_S[13:8] 	<= set_data[5:0];
			base_addr + 24'h000014:		V_SYNC_E[7:0]	<= set_data[7:0];
			base_addr + 24'h000015:		V_SYNC_E[13:8] 	<= set_data[5:0];
			base_addr + 24'h000018:		V_DATA_S[7:0]	<= set_data[7:0];
			base_addr + 24'h000019:		V_DATA_S[13:8] 	<= set_data[5:0];
			base_addr + 24'h00001C:		V_DATA_E[7:0]	<= set_data[7:0];
			base_addr + 24'h00001D:		V_DATA_E[13:8] 	<= set_data[5:0];
			base_addr + 24'h000020:		H_SYNC_S[7:0]	<= set_data[7:0];
			base_addr + 24'h000021:		H_SYNC_S[13:8] 	<= set_data[5:0];
			base_addr + 24'h000024:		H_SYNC_E[7:0]	<= set_data[7:0];
			base_addr + 24'h000025:		H_SYNC_E[13:8] 	<= set_data[5:0];
			base_addr + 24'h000028:		H_ACTIVE[7:0]	<= set_data[7:0];
			base_addr + 24'h000029:		H_ACTIVE[13:8] 	<= set_data[5:0];
			base_addr + 24'h00002C:		VH_POLORITY		<= set_data[1:0];
			base_addr + 24'h000030:		P_LAN_NUM		<= set_data[3:0];
		endcase	
end
assign	work_en = work_mode[0];
assign	dp_rec_mode = work_mode[1];

assign	p_width = H_ACTIVE;
assign	lan_num = P_LAN_NUM;

always@(posedge oclk)
	if (P_LAN_NUM == 8)
		p_length = H_ACTIVE[11:3];
	else if (P_LAN_NUM == 2)
		p_length = H_ACTIVE[11:1];
	else
		p_length = H_ACTIVE[11:2];
		
/*always@(posedge pclk)
	if (half_flag == 1)
		de_max <= H_ACTIVE[11:3] - 2;
	else
		de_max <= H_ACTIVE[11:2] - 2;
*/
always@(posedge oclk)
	de_max <= p_length;
	
//**************************************************************/
//              时序计数
//**************************************************************/
//像素计数
always  @(posedge oclk or negedge resetb)
    if (resetb == 0)
        p_count <= 0;
//    else if ((v_sync == 1) || (f2_end == 1))
	else if (work_en == 0)
    	p_count <= 0; 
    else if (p_end == 1)
        p_count <= 0;
	else
        p_count <= p_count + 1;
                
//一行像素结束
always  @(posedge oclk)
    if (resetb == 0 )
        p_end <= 0;
//	else if ((v_sync == 1) || (f2_end == 1))
	else if (work_en == 0)
    	p_end <= 0;     
    else if (p_count == H_MAX)
        p_end <= 1;
    else
        p_end <= 0;
                
//行计数
always  @(posedge oclk or negedge resetb)
    if (resetb == 0 )
        h_count <= 0;
//	else if ((v_sync == 1) || (f2_end == 1))
	else if (work_en == 0)
    	h_count <= 0;     
    else if (p_end == 1)begin
        if (h_end == 1)
        	h_count <= 0;
        else
            h_count <= h_count + 1;
        end

//一帧最后一行
always  @(posedge oclk or negedge resetb)
    if (resetb == 0 )
        h_end <= 0;
//	else if ((v_sync == 1) || (f2_end == 1))
	else if (work_en == 0)
        h_end <= 0;
    else if (h_count == V_MAX)
        h_end <= 1;
    else 
        h_end <= 0;
                
//**************************************************************/
//              显示输出时序
//**************************************************************/
//帧同步
always  @(posedge oclk)
    if ((h_count < V_SYNC_S) || (h_count >= V_SYNC_E))
        vsout <= 1'b0;
    else
        vsout <= 1'b1;

//行同步
always  @(posedge oclk)
	if (((h_count < V_DATA_S) || (h_count >= V_DATA_E)) && (dp_rec_mode == 1))
        hsout <= 1'b0;
	else if ((p_count < H_SYNC_S) || (p_count >= H_SYNC_E))
        hsout <= 1'b0;
    else
        hsout <= 1'b1;

//数据有效
always  @(posedge oclk)
	if ((h_count < V_DATA_S) || (h_count >= V_DATA_E))
        deout_t <= 1'b0;
    else if (p_count >= p_length)
        deout_t <= 1'b0;
    else
        deout_t <= 1'b1;

always  @(posedge oclk)
	deout <= deout_t;

//测试数据
always  @(posedge oclk)
	if (deout_t == 0)
		dout <= 48'h0;
	else
		 case (test_mode)
		//case (test_mode_in)
			8'h01:		dout <= {2{h_count[7:0], h_count[7:0], h_count[7:0]}};
			8'h02:		dout <= {{3{p_count[6:0], 1'b1}}, {3{p_count[6:0], 1'b0}}};
			8'h03:		dout <= {2{8'hFF, 8'hFF, 8'hFF}};
			8'h04:		dout <= {2{8'h00, 8'h00, 8'hFF}};
			8'h05:		dout <= {2{8'h00, 8'hFF, 8'h00}};
			8'h06:		dout <= {2{8'hFF, 8'h00, 8'h00}};
			// 8'h07:		dout <= {{h_count[11:0], p_count[10:0], 1'b1}, {h_count[11:0], p_count[10:0], 1'b0}};
			8'h07:		dout <= {2{8'h00, 8'h00, 8'h00}};
			default:	dout <= {{3{p_count[6:0], 1'b1}}, {3{p_count[6:0], 1'b0}}};
		endcase

//**************************************************************/
//              TCON输出时序
//**************************************************************/
//mini LVDS 包同步
always  @(posedge oclk)
	if ((h_count < V_DATA_S - 1) || (h_count >= V_DATA_E + 9 ))
        TP <= 1'b0;
	else if ((p_count < H_SYNC_S) || (p_count >= H_SYNC_E))
        TP <= 1'b0;
    else
        TP <= 1'b1;

//POL
always  @(posedge oclk or negedge resetb)
	if (resetb == 0)
		POL <= 0;
	else if ((h_count == V_DATA_E + 10) && (p_end == 1))
        POL <= POL + 1;

//STV
always  @(posedge oclk or negedge resetb)
	if (resetb == 0)
		STV <= 0;
	else if (h_end == 1)
		STV <= 0;
	else if ((h_count == V_DATA_S - 5) && (p_count == H_SYNC_S - 97 ))
        STV <= 1;
	else if ((h_count == V_DATA_S - 1) && (p_count == H_SYNC_S - 229 ))
        STV <= 0;

//CLR
always  @(posedge oclk or negedge resetb)
	if (resetb == 0)
		CLR <= 0;
	else if (h_end == 1)
		CLR <= 0;
	else if ((h_count == V_DATA_E + 5) && (p_count == H_SYNC_S - 331))
        CLR <= 1;
	else if ((h_count == V_DATA_E + 7) && (p_count == 296 ))
        CLR <= 0;

//CPV1
always  @(posedge oclk)
	if ((h_count < V_DATA_S - 3) || (h_count > V_DATA_E + 1))
		CPV1 <= 0;
	else if ((p_count > H_SYNC_S - 590 ) && (p_count < H_SYNC_S - 246))
		CPV1 <= 1;
	else
		CPV1 <= 0;

//CPV2
always  @(posedge oclk)
	if ((h_count < V_DATA_S - 1) || (h_count > V_DATA_E + 4))
		CPV2 <= 0;
	else if ((p_count > H_SYNC_S - 590) && (p_count < H_SYNC_S - 246))
		CPV2 <= 1;
	else
		CPV2 <= 0;

//**************************************************************/
//              帧缓冲时序
//**************************************************************/
//帧缓冲输出
always  @(posedge oclk)
    if ((p_count < p_length) && (h_count >= V_DATA_S - 1) && (h_count < V_DATA_E - 1))
        deout_p <= 1;
    else
        deout_p <= 0;
        
//帧缓冲预读
always  @(posedge oclk)
    if ((p_count < p_length) && (h_count >= V_DATA_S - 2) && (h_count < V_DATA_E - 2))
        deout_pp <= 1;
    else
        deout_pp <= 0;
        
//切换时钟域
always  @(posedge pclk) begin
	vsout_t 	<= {vsout_t[3:0], vsout};
	deout_p_t 	<= {deout_p_t[3:0], deout_p};
	deout_pp_t 	<= {deout_pp_t[3:0], deout_pp};
end

//缓冲帧
always @( * )
	vs_a <= vsout_t[3];

//缓冲预读
always @(posedge pclk)
	if (deout_pp_t[2:1] == 2'b01)
		de_pre <= 1;
	else
		de_pre <= 0;
	
//缓冲输出开始
always @(posedge pclk or negedge resetb)
	if (resetb == 0)
		de_flag <= 0;
	else if (vs_a == 1)
		de_flag <= 0;
	else if (deout_p_t[2:1] == 2'b01)
		de_flag <= 1;
	else if (de_end == 1)
		de_flag <= 0;

//缓冲输出长度计数
always @(posedge pclk)
	if (de_flag == 0)
		de_count <= 0;
	else
		de_count <= de_count + 1;

//缓冲输出长度计数
always @(posedge pclk)
	if (de_count == de_max)
		de_end <= 1;
	else
		de_end <= 0;
        
//缓冲输出行计数
always @(posedge pclk or negedge resetb)
	if (resetb == 0)
		h_num <= 0;
	else if (vs_a == 1)
		h_num <= 0;
	else if (deout_p_t[3:2] == 2'b10)
		h_num <= h_num + 1;
        
//测试数据
always  @(posedge pclk)
	if (de_flag == 0)
		dout_t <= 32'h0;
	else
		case (test_mode)
			8'h01:		dout_t <= {2{h_num[7:0], h_num[7:0], h_num[7:0]}};
			8'h02:		dout_t <= {{3{de_count[6:0], 1'b1}}, {3{de_count[6:0], 1'b0}}};
			8'h03:		dout_t <= {2{8'hFF, 8'hFF, 8'hFF}};
			8'h04:		dout_t <= {2{8'h00, 8'h00, 8'hFF}};
			8'h05:		dout_t <= {2{8'h00, 8'hFF, 8'h00}};
			8'h06:		dout_t <= {2{8'hFF, 8'h00, 8'h00}};
			8'h07:		dout_t <= {2{h_num[11:0], 2'b00, de_count[9:0]}};
			default:	dout_t <= {2{h_num[7:0], h_num[7:0], h_num[7:0]}};
		endcase

always  @(posedge pclk)
	de_a <= de_flag;
       
//************************************************/
//      调试信号
//************************************************/
assign  tout = 0;

endmodule
